package com.meatball.authorization.service.impl

import com.meatball.authorization.data.dto.CreateUserParams
import com.meatball.authorization.data.dto.UpdateUserParams
import com.meatball.authorization.data.dto.UserResponse
import com.meatball.authorization.data.entity.RoleEntity
import com.meatball.authorization.data.entity.UserEntity
import com.meatball.authorization.repository.UserRepository
import com.meatball.authorization.service.UserService
import com.meatball.core.config.ROLE_NAME_EXISTS
import com.meatball.core.config.TARGET_AND_RESOURCE_MISMATCH
import com.meatball.core.config.USERNAME_EXISTS
import com.meatball.core.exception.AttributeMismatchWarning
import com.meatball.core.exception.DataAlreadyExistsException
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import java.util.*

/**
 * TODO 用户管理服务实现层
 *
 * @author 张翔宇
 * @since 2024年3月26日
 */
@Service
class UserServiceImpl(
    private val userRepository: UserRepository,
    private val passwordEncoder: PasswordEncoder
) : UserService {
    override fun crate(data: CreateUserParams) {
        userRepository.findByUsername(data.username)?.also {
            throw DataAlreadyExistsException(USERNAME_EXISTS)
        }
        userRepository.save(UserEntity(
            username = data.username,
            nickname = data.nickname,
            realName = data.realName,
            password = passwordEncoder.encode(data.password),
            avatar = data.avatar
        ))
    }

    override fun readAll(): Iterable<UserResponse> {
        return toUserResponse(userRepository.findAll())
    }

    override fun findRolesByUsername(username: String): List<String> {
        return userRepository.findByUsername(username)
            ?.roles?.map { it.name } ?: emptyList()
    }

    override fun readById(id: Long): Optional<UserEntity> {
        return userRepository.findById(id)
    }

    override fun update(id: Long, params: UpdateUserParams) {
        if (id != params.id) throw AttributeMismatchWarning(TARGET_AND_RESOURCE_MISMATCH)
        userRepository.countByUsernameAndIdIsNot(params.username, id).takeIf { it > 0 }?.also {
            throw DataAlreadyExistsException(USERNAME_EXISTS)
        }
        // 更新用户信息
        userRepository.findById(id).ifPresent {
            it.username = params.username
            it.nickname = params.nickname
            it.realName = params.realName
            it.avatar = params.avatar
            userRepository.save(it)
        }
    }

    override fun delete(id: Long) {
        userRepository.deleteById(id)
    }

    private fun toUserResponse(list: Iterable<UserEntity>) : List<UserResponse> {
        return list.map { UserResponse(
            id = it.id,
            username = it.username,
            realName = it.realName,
            avatar = it.avatar
        ) }.toList()
    }
}